<!--
 * @Description:
 * @version:
 * @Author: 尹鹏孝
 * @Date: 2023-02-28 15:25:02
 * @LastEditors: 尹鹏孝
 * @LastEditTime: 2023-03-01 11:50:10
-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>this和原型</title>
</head>
<body>
    <script>
        function identify(){
           let keys = this.name.toUpperCase();
           console.log(keys);
           return keys;
        }

        function speak(){
            var greeting="Hello im "+ identify.call(this);
            console.log(greeting);
        }

        var me = {
            name:"Kyle"
        }
        var you={
            name:"Reader"
        }

        identify.call(me);
        identify.call(you);

        speak.call(me);
        speak.call(you);


        function foo(num){
            console.log("foo:",num);
            this.count++;
        }

        foo.count=0;
        var i=0;
        for(i=0;i<10;i++){
            if(i>5){
                // foo(i);foo
                foo.call(foo,i);
            }
        }

        console.log(foo.count);

        function newsFoo(){
            var a=2;
            this.barer();
        }

        function barer(){
            console.log(this.a);
        }

        foo();
        //当使用this查找词法作用域里的内容，是无法实现的。

        //javascript的this到底是什么？
        // this是在运行时候绑定的，不是在编写时候绑定，她的上下文取决于函数调用时候的各种条件，this绑定和函数声明的位置没有关系，只取决于函数的调用方式。
        // //函数或者对象的调用栈(函数调用链)和调用位置->一根据程序关系和运行顺序分析，二、依赖调试器或者浏览器调试工具，打断点或者增加debugger
        function baring(){
            console.log("baz");
            bare();
        }

        function bare(){
            console.log("bare");
            fon();
        }

        function fon(){

            console.log("foo")
        }
        baring();

        // 函数执行过程中调用未知如何决定this的绑定对象
        // 找到调用规则判断this需要应用以下四条规则中的哪一条。

        // 一、默认绑定：独立函数调用，这是应用其他规则无效后的默认规则
        var apple = "is an Apple"
        function foodNess(){
            // "use strict";
            console.log(this.apple);
        }
        foodNess();


        // 二、this的隐式绑定，隐式绑定时候this丢失很常见

        function fooNotLoss() {
                console.log(this.aNotLoss);
            }
            var obj2NotLoss = {
                aNotLoss: 42,
                fooNotLoss: fooNotLoss
            };
            var obj1NotLoss = {
                aNotLoss: 2,
                obj2NotLoss: obj2NotLoss
            };
            obj1NotLoss.obj2NotLoss.fooNotLoss();
        function fooBook() {
                console.log(this.aBook);
            }
            function doFooBook(fn) {
                // fn 其实引用的是 foo
                // fn();
                //fn.call(fn,null); // <-- 调用位置！
                return function(obj){
                    fn.call(obj);
                }
            }
            var objBook = {
                aBook: 2,
                fooBook: fooBook
            };
            var aBook = "oops, global"; // a 是全局对象的属性
            //  doFooBook(objBook.fooBook)
            //doFooBook(objBook.fooBook)(objBook); // "oops, global"
            //三、显式绑定，call,apply和bind.apply和call的第一个参数是对象，他们会把这个对象绑定到this,接着在调用这个函数时指向this。因为你可以直接指定this的绑定对象。
            // 显式绑定最为重要的方法就是调用bind函数，进行绑定，bind会返回一个硬编码的新函数，他会把设置为this的上下文掉用原始函数。
            // API调用上下文

            function vpn(el){
                console.log(el.id)
            }

            var objVPn={
                id:"awesome"
            }

            let everyOne = [{
                    id: "1 awesome"
                }, {
                    id: "2 awesome"
                }, {
                    id: "3 awesome"
                }]

            everyOne.forEach(vpn);
            //四、new绑定
            // javascript 函数和对象的误解
            // something = new MyCLass();
            // 使用new调用一个函数发生构造函数调用时候，会自动执行以下四步骤操作
            // 1、创建一个全新对象
            // 2、创建这个对象的原型连接
            // 3、对这个新对象会绑定到函数的this
            // 4、如果函数没有返回其他对象，那么new表达式中的函数会自动返回这个新对象
                function fooPeople(a){
                    this.a=a;
                }
                var anPeople = new fooPeople(2);
                console.log(anPeople.a);


                // this绑定的优先级

                console.log("优先级：======================>");
                function useThis(){
                    console.log(this.a);
                }

                var objectOne={
                    a:2,
                    useThis: useThis,
                };
                var objectTwo= {
                        a: 3,
                        useThis: useThis,
                    };

                    objectOne.useThis();
                    objectTwo.useThis();

                    objectOne.useThis.call(objectTwo);
                    objectTwo.useThis.call(objectOne);

                    console.log("显式优先级更高");

                    console.log("new 和隐式优先级谁更高？");
                    function lake(something){
                        this.a = something;
                    }

                    var good={
                        lake: lake,
                    }

                     var bead = {

                        }
                    good.lake(2);


                    console.log(good.a);

                    // console.log()
                    good.lake.call(bead,3);


                    console.log(bead.a);
                    var superMan = new good.lake(4);
                    console.log(good.a);
                    console.log(superMan.a);

                    console.log("new 优先级比隐式绑定this更高，new无法和call,apply一起使用，");


                    //new和显示绑定哪个优先级更高呢？new和apply和call无法一起使用，但是可以使用bind来比较
                    function right(sm){
                        this.a=sm;
                    }

                    var err={};
                    var quine = right.bind(err);

                    quine(4444);
                    console.log(err.a);
                    var master = new quine(3);


                    console.log(err.a);
                    console.log(master.a);


                    function titleLeader(p1,p2){
                        this.val = p1+p2;
                    }

                    var lhj = titleLeader.bind(null,"p1");
                    var question = new lhj("p2");
                    console.log(question.val);
                    console.log("this的new 绑定高于this硬绑定");

                    console.log("判断优先级在哪个位置应用的是哪条规则，按照下面的顺序进行判断");

                    console.log("1、函数是否在new中调用，如果是，this绑定的是新创建的对象");
                    console.log("2、函数是否通过call， apply，bind或者硬绑定调用，如果是this绑定是指定的对象");
                    console.log("3、函数是否在某个上下文对象中调用（隐式绑定），如果是，this绑定的是那个上下文对象");
                    console.log("4、如果都不是的话，使用默认绑定，如果在严格模式下，就是undefined，否则就绑定到全局对象");


                    console.log("被忽略的this,当帮null,undefined,作为this的绑定对象传入call,apply,或者bind,这些值在调用时候被忽略，实际应用的是默认绑定规则：");


                    function babalba(){
                        console.log(this.a);
                    }

                    var a=2;
                    babalba.call(null);

                    function dbd(a,b){
                        console.log("a:"+a,"b:"+b);
                    }
                    dbd.apply(null,[1,2]);

                    var tools =  dbd.bind(null,2);

                    tools(3);


                    console.log("Object.create(null)和{}区别：")
                    console.log("Object.create(null)比{}更空，因为不存在prototype这个委托，代码的可读性更高，更安全")

                    console.log("创建一个间接引用：");
                    console.log(`
                        function foo(){
                            console.log(this.a);
                        }

                        var a=2;
                        var o={
                            a:3,
                            foo:foo
                        }

                        var p = {
                            a:4
                        }

                        o.foo();
                        (p.foo=o.foo)();

                        p.foo=o.foo这个返回值是目标函数的引用，目标函数foo是属于全局而不是p.foo或者o.foo。那么这样就是默认绑定。

                    `);
                    console.log("对于默认绑定来说，决定this绑定对象的并不是调位置是否处于严格模式而是函数体是否处于严格模式，如果函数体处于严格模式，this就会绑定到undefined，否则就会绑定到全局对象")


                    console.log(`箭头函数的this`);
                    console.log(`function myPosition(){
                        return (a)=>{
                            console.log(this.a);
                        }
                    }
                        var obj1={a:2};
                        var obj2={
                            a:3,
                        }
                        var bar = foo.call(obj1);
                        bar.call(obj2);
                    `)

                    // 运用this改变作用域的方法：
                    // 1、self=this;
                    // 2、箭头函数
                    // 3、call,apply,bind
                    // 4、new
                    // 5、对象绑定
                    // 6、隐式绑定
                    // 7、全局作用域

                    // 错误做法是用箭头函数和self=this来绑定







    </script>
</body>
</html>